﻿using InfoPathHelpers.TemplateExplorer;
using InfoPathHelpers.UserRoles;
using InfoPathHelpers.Xml;
using Microsoft.Office.InfoPath;
using System;
using System.Xml;
using System.Xml.XPath;

namespace InfoPathHelpers
{
    public sealed class FormContext : IDataSourceContext
    {
        private static XmlFormHostItem _Form;
        private FixedPositionNavigator _Root;
        private string _Prefix;
        private string _NamespaceURI;
        private string _Name;
        
        public FormContext(XmlFormHostItem form)
        {
            _Form = form;
            _Root = new FixedPositionNavigator(form.CreateNavigator());
            _Name = form.MainDataSource.Name;
            var ManifestExplorer = new ManifestExplorer(this);
            UserRoles = ManifestExplorer.GetUserRoles();            
        }

        public FormTemplate Template
        {
            get { return _Form.Template; }
        }

        public string TemplateURN
        {
            get
            {
                return XmlHelpers.GetProcessingInstructionAttribute(Navigator, "mso-infoPathSolution", "name");
            }
        }

        public string SolutionVersion
        {
            get
            {
                return XmlHelpers.GetProcessingInstructionAttribute(Navigator, "mso-infoPathSolution", "solutionVersion");
            }
            set
            {
                XmlHelpers.SetProcessingInstructionAttribute(Navigator, "mso-infoPathSolution", "solutionVersion", value);
            }
        }

        internal string CodeNamespace
        {
            get { return _Form.GetType().Namespace; }
        }

        public string NamespacePrefix
        {
            get 
            { 
                if(string.IsNullOrEmpty(_Prefix))
                {
                    _Prefix = _Root.SelectSingleNode("*").Prefix;
                }
                return _Prefix; 
            }
        }

        public string NamespaceURI
        {
            get
            {
                if (string.IsNullOrEmpty(_NamespaceURI))
                {
                    _NamespaceURI = _Root.SelectSingleNode("*").NamespaceURI;
                }
                return _NamespaceURI;
            }
        }

        public string Uri
        {
            get { return _Form.Uri; }
        }

        public HtmlTaskPane CustomTaskPane
        {
            get
            {
                if (_Form.TaskPanes == null)
                {
                    throw new InvalidOperationException("TaskPanes has not been intialized. " +
                        "Custom task panes can only be accessed after the form has loaded.");
                }
                return (HtmlTaskPane)_Form.TaskPanes[0];
            }
        }

        public DataSourceCollection DataSources
        {
            get { return _Form.DataSources; }
        }

        public DataConnectionCollection DataConnections
        {
            get { return _Form.DataConnections; }
        }

        public ViewInfoCollection Views
        {
            get { return _Form.ViewInfos; }
        }

        public UserRoleCollection UserRoles { get; private set; }

        public string Name
        {
            get { return _Name; }
        }

        public bool HasErrors
        {
            get { return _Form.Errors.Count > 0; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public void SaveAs(string fileName)
        {
            _Form.SaveAs(fileName);
        }

        public FixedPositionNavigator Root
        {
            get { return _Root; }
        }

        public XPathNavigator Navigator
        {
            get { return _Root.Clone(); }
        }

        public IXmlNamespaceResolver NamespaceManager
        {
            get { return _Form.NamespaceManager; }
        }

        public XPathNavigator SelectSingleNode(string xPath)
        {
            return _Root.SelectSingleNode(xPath, NamespaceManager);
        }

        public XPathNodeIterator Select(string xPath)
        {
            return _Root.Select(xPath, NamespaceManager);
        }

        public object Evaluate(string xPath)
        {
            return _Root.Evaluate(xPath, _Form.NamespaceManager);
        }

        /// <summary>
        /// Sets the UserRole of the form according to roles defined using UserRoles.AddAssignment().
        /// This is required due to InfoPath taking a very long time to determine user role on
        /// non-domain machines.
        /// </summary>
        public void SetCurrentUsersRole()
        {
            if (_Form.New && UserRoles.HasInititatorRole)
            {
                // InfoPath handles setting initiator role.
                return;
            }

            var UserRole = UserRoles.GetCurrentRole();

            if (UserRole == null)
            {
                // InfoPath sets default role.
                return;
            }

            // We set the role from AD membership.
            _Form.UserRole = UserRole.Name;
        }
    }
}
